﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using King.Engine.Content;
using King.Engine.Core;
using Microsoft.Xna.Framework;

namespace King.Engine.GameObjects
{
    /// <summary>
    /// A game object with a single sprite
    /// </summary>
    public abstract class SimpleSpriteObject : GameObject
    {
        #region Fields

        protected Texture2D _texture;
        private float _drawDepth;
        private Rectangle _drawBounds;

        #endregion


        #region Constructor

        protected SimpleSpriteObject(string spriteName, float drawDepth)
        {
            _drawDepth = drawDepth;
            ChangeSprite(spriteName);
        }

        internal SimpleSpriteObject()
        {

        }

        #endregion


        #region Public Methods

        /// <summary>
        /// Change the sprite to a new sprite of the given name
        /// </summary>
        public void ChangeSprite(string spriteName)
        {
            _texture = ContentLoader.Get<Texture2D>(spriteName);
        }

        protected override void OnMove()
        {
            Rectangle spriteBounds = Bounds;
            spriteBounds.Location = Point.Zero;

            _drawBounds = Bounds;
            //_drawBounds.Offset(spriteBounds.Center);

            base.OnMove();
        }

        protected override void DrawObject()
        {
            Screen.Draw(this.IsGUI, _texture, _drawBounds, null, Color.White, this.Rotation, RotationOrigin, SpriteEffects.None, _drawDepth);
        }

        #endregion
    }

    public abstract class TileSpriteObject : SimpleSpriteObject
    {
        #region Fields

        protected Texture2D _texture;
        private float _drawDepth;

        #endregion

        #region Constructor

        protected TileSpriteObject(string tileSpriteName, float drawDepth, int tileWidth, int tileHeight, int rows, int cols)
        {
            _drawDepth = drawDepth;
            GenerateTexture(tileSpriteName, tileWidth, tileHeight, rows, cols);
        }

        #endregion


        #region Protected Methods

        protected override void DrawObject()
        {
            Screen.Draw(this.IsGUI, _texture, this.Bounds, _drawDepth);
        }

        #endregion

        #region Public Methods

        public void SetBounds(int x, int y)
        {
            Bounds = new Rectangle(x, y, _texture.Width, _texture.Height);
        }

        #endregion

        #region Private Methods

        void GenerateTexture(string tileSpriteName, int tileWidth, int tileHeight, int rows, int cols)
        {
            Texture2D tileSprite = ContentLoader.Get<Texture2D>(tileSpriteName);

            GraphicsDevice device = King.Engine.Core.Game.GraphicDevice;
            RenderTarget2D target = new RenderTarget2D(device, tileWidth * cols, tileHeight * rows, false, SurfaceFormat.Color, DepthFormat.None);

            device.SetRenderTarget(target);
            device.Clear(Color.Transparent);
            SpriteBatch spriteBatch = new SpriteBatch(device);

            spriteBatch.Begin();

            for (int x = 0; x < cols; x++)
                for (int y = 0; y < rows; y++)
                {
                    Rectangle drawRect = new Rectangle(tileWidth * x, tileHeight * y, tileWidth, tileHeight);
                    spriteBatch.Draw(tileSprite, drawRect, Color.White);
                }

            spriteBatch.End();

            device.SetRenderTarget(null);

            _texture = (Texture2D)target;
            Bounds = _texture.Bounds;
        }

        #endregion
    }

    /// <summary>
    /// A game object that supports multiple sprites
    /// </summary>
    /// <typeparam name="T">Each sprite is keyed by a value of type T. This should be an enum</typeparam>
    public abstract class SpriteObject<T> : SimpleSpriteObject
    {

        #region Fields

        public Dictionary<T, Texture2D> _sprites;

        #endregion


        #region Constructor

        /// <summary>
        /// Create a SpriteObject
        /// </summary>
        /// <param name="_spriteNames">Dictionary that maps T values to sprite names</param>
        /// <param name="drawDepth">The draw depth of the sprites</param>
        public SpriteObject(Dictionary<T, string> _spriteNames, float drawDepth, T initialSprite)
        {
            _sprites = _spriteNames.ToDictionary(kv => kv.Key, 
                                                 kv => ContentLoader.Get<Texture2D>(kv.Value));
            SetSprite(initialSprite);
        }
        
        #endregion


        #region Public Methods

        /// <summary>
        /// Set the sprite from the given key
        /// </summary>
        public void SetSprite(T sprite)
        {
            _texture = _sprites[sprite];
        }

        #endregion

    }
}
